import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
import events from '@/utils/eventBus';
import EVENTBUS_TYPES from '@/pages/Recruitment/Interview/utils/EVENTBUS_TYPES';

/**
 * 面试专用 websocket
 */
class InterviewSocketUtil {
    user; // userCode, localstorage 中的那个

    roomId; // 同roomId，可接收到广播

    subscribed; // 已订阅的消息

    sendWaitingArr; // 待发送消息

    retrying;

    setIntervalId;

    isConnected;

    defaultEvent; // 录音通用默认事件

    /**
     * @param {string} userCode 用户标识
     * @param {string} roomId 创建socket所需参数，同roomId中可互相广播，例如面试中可用arrangeId充当roomId
     * @param {string} defaultEvent 录音通用默认事件
     */
    constructor(userCode, roomId, defaultEvent) {
        this.subscribed = new Map();
        this.sendWaitingArr = [];
        this.user = userCode; // localStorage.user.userCode
        this.roomId = roomId;
        this.defaultEvent = defaultEvent;
    }

    // 链接socket
    connect() {
        if (this.client && this.isConnected) {
            return;
        }
        try {
            const url = `/api/ws/public/pusher?userCode=${this.user}&roomId=${this.roomId}`;
            const socket = new SockJS(url, null, { timeout: 15000 });
            this.client = Stomp.over(socket);
            this.client.debug = () => {}; // 关闭debug
            this.client.connect(
                {
                    Connection: 'Upgrade',
                    Upgrade: 'websocket'
                },
                this.connectCallback.bind(this),
                this.errorCallback.bind(this)
            );
        } catch (e) {
            this.errorCallback();
        }
    }

    // 链接成功callback
    connectCallback() {
        console.log('链接成功callback!!!!!!!');
        events.emit(EVENTBUS_TYPES.SOCKET_CONNECTED);
        if (this.setIntervalId) {
            clearInterval(this.setIntervalId);
        }

        this.isConnected = true;
        console.log(`%cConnected: ${this.roomId}`, 'color: #87d068;');
        // 订阅连接建立前订阅的事件
        this.subscribed.forEach((subs, type) => {
            this.client.subscribe(
                type, // `jms.topic.${type}`
                msg => {
                    if (Array.isArray(subs)) {
                        subs.map(callback => {
                            if (typeof callback === 'function') {
                                callback({ msg, type });
                            }
                            return '';
                        });
                    }
                }
            );
        });
        // 发送未成功发送的事件
        this.sendWaitingArr.forEach(item => {
            this.send(...item);
        });
        this.sendWaitingArr.length = 0;
    }

    // 链接失败callback
    errorCallback() {
        console.error('%cConnection failed!', 'color: #f50');
        events.emit(EVENTBUS_TYPES.SOCKET_DISCONNECT);
        this.isConnected = false;
        this.retry();
    }

    retry() {
        console.log('Interview >>> Connection failed, trying again');
        let retrying = false;
        if (this.setIntervalId) {
            clearInterval(this.setIntervalId);
        }
        this.setIntervalId = setInterval(() => {
            if (!retrying) {
                console.log('<<< RETRYING');
                retrying = true;
                this.connect(this.user, this.roomId);
            }
        }, 5000);
    }

    /**
     * 消息订阅
     * 如果已经连接则直接订阅，如果尚未连接则存入Map中等待链接成功后订阅消息
     */
    subscribe(subType, eventCallback) {
        if (this.client && this.isConnected) {
            if (Array.isArray(subType)) {
                subType.forEach(s => {
                    // `jms.topic.${s}`
                    this.client.subscribe(s, msg => eventCallback({ msg, type: s }), {
                        ask: 'client-individual'
                    });
                });
            } else {
                // `jms.topic.${subType}`
                this.client.subscribe(subType, msg => eventCallback({ msg, type: subType }), {
                    ask: 'client-individual'
                });
            }
        }
        this.addSubscribeToMap(subType, eventCallback);
    }

    addSubscribeToMap(subType, eventCallback) {
        if (Array.isArray(subType)) {
            subType.map(s => {
                if (this.subscribed.has(s)) {
                    const subCallbacks = this.subscribed.get(s);
                    this.subscribed.set(s, [...subCallbacks, eventCallback]);
                } else {
                    this.subscribed.set(s, [eventCallback]);
                }
                return '';
            });
        } else {
            this.subscribed.set(subType, [eventCallback]);
        }
    }

    /**
     * 发布事件
     * 禁止往jms.topic.【roomId】发布事件，会造成后端bug
     */
    send(body, header = {}) {
        console.log('发布事件', body);
        if (this.client && this.isConnected) {
            this.client.send(this.defaultEvent, header, JSON.stringify(body));
        } else {
            // 连接未建立时，先压入数组中暂存
            this.sendWaitingArr.push([body, header]);
        }
    }

    // 断开链接
    disconnect() {
        if (this.setIntervalId) {
            clearInterval(this.setIntervalId);
        }
        if (this.client && this.isConnected) {
            this.client.disconnect(() => {
                this.isConnected = false;
                this.client = null;
                console.log(`${'%cConnection closed! roomId:'}${this.roomId}`, 'color: #87d068;');
            });
        }
    }
}

export default InterviewSocketUtil;
